#include "StdAfx.h"
#include "SerialSingleton.h"
#include <string>
#include "../Edit.h"
#include "../WidgetWin.h"
#include "../Utility.h"
#include "../RootView.h"
#include "../res.h"
#include "LogAction.h"

SerialSingleton::SerialSingleton(void)
: m_hCom(INVALID_HANDLE_VALUE)
{
}

SerialSingleton::~SerialSingleton(void)
{
	if (m_hCom != INVALID_HANDLE_VALUE)
	{
		CloseHandle(m_hCom);
	}
}

SerialSingleton& SerialSingleton::getInstance()
{
	static SerialSingleton serial;
	return serial;
}

void SerialSingleton::Register(LogAction* log)
{
	register_action_.push_back(log);
}

void SerialSingleton::Unregister(LogAction* log)
{
	// Lock here
	for (std::list<LogAction*>::iterator iter = register_action_.begin();
		iter != register_action_.end(); ++iter)
	{
		if (log == (*iter))
		{
			register_action_.erase(iter);
			break;
		}
	}
}

size_t SerialSingleton::write(const void* buf, size_t count)
{
/*
	std::string str = reinterpret_cast<const char *>(buf);
	Edit* edit = reinterpret_cast<Edit *>(WidgetWin::getInstance().getRootView()->getViewById(ID_EDIT_LOG));

	if (edit)
	{
		edit->appendText(StringToWstring(str));
	}
*/


	DWORD dwWriteByte = 0;
	if (WriteFile(m_hCom, buf, count, &dwWriteByte, NULL))
	{
		return dwWriteByte;
	}

	return 0;
}

size_t SerialSingleton::read(void* buf, size_t count, unsigned int timeout)
{
	COMMTIMEOUTS comtimeout;
	memset(&comtimeout, 0, sizeof(comtimeout));
	comtimeout.ReadTotalTimeoutConstant = timeout;
	SetCommTimeouts(m_hCom, &comtimeout);

	DWORD dwReadByte = 0;
	if (ReadFile(m_hCom, buf, count, & dwReadByte, NULL))
	{
		std::string str = reinterpret_cast<const char *>(buf);
		Edit* edit = reinterpret_cast<Edit *>(WidgetWin::getInstance().getRootView()->getViewById(ID_EDIT_LOG));

		if (edit)
		{
			edit->appendText(StringToWstring(str));
		}

		return dwReadByte;
	}

	return 0;
}

bool SerialSingleton::open(const char* pathname)
{
	if (m_hCom != INVALID_HANDLE_VALUE)
	{
		return false;
	}

	std::string com_port = "\\\\.\\";
	com_port += pathname;

	m_hCom = CreateFileA(com_port.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
	if (m_hCom == INVALID_HANDLE_VALUE)
	{
		DWORD dwError = GetLastError();
		printf("error : %d\r\n", dwError);
		return false;
	}

	DCB dcb;
	memset(&dcb, 0, sizeof(dcb));
	GetCommState(m_hCom, &dcb);

	dcb.BaudRate = 460800;
	dcb.ByteSize = 8;
	dcb.StopBits = ONESTOPBIT;
	dcb.fParity = FALSE;
	dcb.fNull = FALSE;
	dcb.Parity = NOPARITY;
	if(!SetCommState(m_hCom, &dcb))
	{
		printf("set common status error:%d", GetLastError());
		return false;
	}

	Edit* edit = reinterpret_cast<Edit *>(WidgetWin::getInstance().getRootView()->getViewById(ID_EDIT_LOG));

	if (edit)
	{
		edit->appendText(StringToWstring(com_port) + std::wstring(L" Open Successful\n"));
	}


	// start thread.
	serial_thread_ = std::shared_ptr<std::thread>(new std::thread(SerialSingleton::run, this));
	return true;
}

void SerialSingleton::run(SerialSingleton* pThis)
{
	if (pThis == NULL)
	{
		return;
	}

	while (1)
	{
		char szBuff[1024] = { 0 };
		size_t size = SerialSingleton::getInstance().read(szBuff, 1023, 100);
		if (size > 0)
		{
			// Lock here
			for (std::list<LogAction*>::iterator iter = pThis->register_action_.begin();
				iter != pThis->register_action_.end(); ++iter)
			{
				(*iter)->OnData(szBuff, size);
			}
		}
	}
}
